package com.dlc.felear.xiaoensale.dlc_serial_port;

import android.os.Handler;
import android.serialport.SerialPort;

import com.dlc.felear.xiaoensale.utils.MyLog;

import org.simple.eventbus.EventBus;

import java.io.File;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * Created by felear on 2018/5/19.
 */

public class DeviceFactory {

    private static final String TAG = "DeviceFactory";

    // Event
    // 取货开门反馈
    public final static String EVENT_OPEN_DOOR = "event_open_door";
    // 补货门关闭反馈
    public final static String EVENT_SUPPLEMENT_CLOSE = "event_supplement_close";
    // 设备状态
    public final static String EVENT_STATUS = "event_status";
    // 设备错误日志
    public final static String EVENT_STATUS_ERROR = "event_status";
    // 设备日志
    public final static String EVENT_LOG = "event_log";

    private static SerialPort serialPort;
    private static String mPort = "/dev/ttyS1";
    private static int mBt = 115200;

    // 同步锁
    private static BlockingQueue<byte[]> ordersQueue = new ArrayBlockingQueue<byte[]>(100);

    private static Thread writeThread = new Thread() {
        @Override
        public void run() {
            try {
                while (true) {
                    byte[] orders = ordersQueue.take();
                    // 发送普通指令
                    serialPort.getOutputStream().write(orders);

                    // 打印指令
                    byte2hex(orders, "send");

                    // 睡眠，防止数据粘包
                    Thread.sleep(100);

                    // 发送查询设备状态指令
                    if ((orders[3] & 0xff) != 0xA4) {

                        byte[] statusOrders = getStatusOrders();
                        serialPort.getOutputStream().write(statusOrders);
                        // 打印指令
                        byte2hex(statusOrders, "send");

                        // 睡眠，防止数据粘包
                        Thread.sleep(100);
                    }

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    private static Thread readThread = new Thread() {
        @Override
        public void run() {
            try {
                serialPort = new SerialPort(new File(mPort), mBt, 0);

                // 监听接收消息线程
                int b, readLen;
                byte[] buf = new byte[64];
                while (true) {
                    byte[] orders = new byte[64];
                    readLen = 0;
                    while (readLen < 4 || readLen < orders[2] + 2) {
                        b = serialPort.getInputStream().read(buf);
                        for (int i = 0; i < b; i++) {
                            if (readLen == 0 && buf[i] != (byte) 0xAA) {
                                continue;
                            }
                            orders[readLen++] = buf[i];
                        }
                    }

                    if (readLen > 0) {
                        String receiver = byte2hex(orders, "receiver " + readLen);
                        // 解析指令
                        switch (orders[3] & 0xff) {
                            case 0xb1:
                                // 取货反馈
                                DeviceBean deviceBean = new DeviceBean((orders[4] << 8) | (orders[5] & 0xff)
                                        , (orders[6] << 8) | (orders[7] & 0xff)
                                        , (orders[8] << 8) | (orders[9] & 0xff)
                                        , orders[10] & 0xff);
                                EventBus.getDefault().post(deviceBean, EVENT_OPEN_DOOR);
                                MyLog.e(TAG, "run: " + deviceBean);
                                break;
                            case 0xb2:
                                // 补货开门
                                EventBus.getDefault().post(orders[4] + "号门已开", EVENT_SUPPLEMENT_CLOSE);
                                break;
                            case 0xb3:
                                // 补货关门
                                EventBus.getDefault().post(orders[4] + "号门已关", EVENT_SUPPLEMENT_CLOSE);
                                break;
                            case 0xb4:
                                // 设备状态
                                EventBus.getDefault().post(receiver, EVENT_STATUS);
                                break;
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };


    public static void init() {

        // 重新init
        if (serialPort != null) {
            serialPort.close();
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    // 初始化接收硬件回复指令线程
                    readThread.start();
                    writeThread.start();
                }
            }, 1000);
        } else {
            // 初始化接收硬件回复指令线程
            readThread.start();
            writeThread.start();
        }

    }

    private static String byte2hex(byte[] buffer, String method) {
        String h = "";

        for (int i = 0; i < buffer[2] + 2; i++) {
            String temp = Integer.toHexString(buffer[i] & 0xFF);
            if (temp.length() == 1) {
                temp = "0" + temp;
            }
            h = h + " " + temp;
//            MyLog.e(TAG, "byte2hex: " + h);
        }

        if (buffer[2] != 0) {
            MyLog.e(TAG, method + " : " + h);
            EventBus.getDefault().post(method + " : " + h, EVENT_LOG);
        }

        return h;
    }

    private static void calculatorSum(byte[] orders) {
        for (int i = 0; i < orders.length - 1; i++) {
            orders[orders.length - 1] += orders[i];
        }
    }

    private static void sendOrders(byte[] orders) {
        try {
            ordersQueue.put(orders);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 指令区
     */
    public static class DeviceBean {
        public int x;
        public int y;
        public int z;
        public int num;

        public DeviceBean(int x, int y, int z, int num) {
            this.x = x;
            this.y = y;
            this.z = z;
            this.num = num;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;

            DeviceBean that = (DeviceBean) o;

            if (x != that.x)
                return false;
            if (y != that.y)
                return false;
            return z == that.z;
        }

        @Override
        public int hashCode() {
            int result = x;
            result = 31 * result + y;
            result = 31 * result + z;
            return result;
        }

        @Override
        public String toString() {
            return "DeviceBean{" +
                    "x=" + x +
                    ", y=" + y +
                    ", z=" + z +
                    ", num=" + num +
                    '}';
        }
    }

    public static void openDoor(List<DeviceBean> deviceBeanList) {
        for (DeviceBean deviceBean : deviceBeanList) {
            for (int i = 0; i < deviceBean.num; i++) {
                openDoor(deviceBean.x
                        , deviceBean.y
                        , deviceBean.z
                        , 1);
            }
        }
    }

    // 开门 出货
    private static void openDoor(int x, int y, int z, int num) {
        byte[] orders = new byte[12];
        // 帧头
        orders[0] = (byte) 0xAA;
        orders[1] = (byte) 0xAA;

        // 指令长度
        orders[2] = (byte) (orders.length - 2);

        // 指令类型
        orders[3] = (byte) 0xA1;

        // 对应门
        // x高位
        orders[4] = (byte) ((x & 0xFF00) >> 8);
        // x地位
        orders[5] = (byte) (x & 0xFF);

        // y高位
        orders[6] = (byte) ((y & 0xFF00) >> 8);
        // y地位
        orders[7] = (byte) (y & 0xFF);

        // z高位
        orders[8] = (byte) ((z & 0xFF00) >> 8);
        // z地位
        orders[9] = (byte) (z & 0xFF);
        orders[10] = (byte) num;
        // 以下为固定调用
        // 商品数量
        calculatorSum(orders);
        // 发送指令
        sendOrders(orders);
    }

    // 补货 开门
    public static void supplementOpen(int num) {
        byte[] orders = new byte[6];

        //补货帧头
        orders[0] = (byte) 0xAA;
        orders[1] = (byte) 0xAA;

        //指令长度
        orders[2] = (byte) (orders.length - 2);

        //指令类型
        orders[3] = (byte) 0xA2;

        //对应门
        orders[4] = (byte) num;

        // 以下为固定调用
        calculatorSum(orders);
        // 发送指令
        sendOrders(orders);
    }

    // 补货 开门
    public static void supplementClose(int num) {
        byte[] orders = new byte[6];

        //补货帧头
        orders[0] = (byte) 0xAA;
        orders[1] = (byte) 0xAA;

        //指令长度
        orders[2] = (byte) (orders.length - 2);

        //指令类型
        orders[3] = (byte) 0xA3;

        //对应门
        orders[4] = (byte) num;

        // 以下为固定调用
        calculatorSum(orders);
        // 发送指令
        sendOrders(orders);
    }

    // 查询机器状态
    public static void queryStatus() {
        byte[] orders = getStatusOrders();
        // 发送指令
        sendOrders(orders);
    }

    private static byte[] getStatusOrders() {
        byte[] orders = new byte[6];

        //补货帧头
        orders[0] = (byte) 0xAA;
        orders[1] = (byte) 0xAA;

        //指令长度
        orders[2] = (byte) (orders.length - 2);

        //指令类型
        orders[3] = (byte) 0xA4;

        //对应门
        orders[4] = (byte) 0x00;

        // 以下为固定调用
        calculatorSum(orders);
        return orders;
    }


}
